package com.ttg.web.service.job.impl;

import com.google.common.util.concurrent.ListenableFuture;
import com.ttg.common.annotation.TaskRunMethod;
import com.ttg.common.dto.TaskBaseDTO;
import com.ttg.common.enums.CreditFlagEnum;
import com.ttg.common.enums.LivenessMctConfigEnum;
import com.ttg.common.enums.UseCreditFlagEnum;
import com.ttg.common.exception.BaseException;
import com.ttg.common.utils.BigDecimalUtils;
import com.ttg.common.vo.TaskResultVO;
import com.ttg.model.dto.job.IndustryDepositDTO;
import com.ttg.model.dto.job.IndustryScoreDTO;
import com.ttg.model.po.AccountInfoPO;
import com.ttg.model.pojo.LivenessMctConfig;
import com.ttg.model.vo.*;
import com.ttg.model.pojo.CostManageIndustryDepositLoan;
import com.ttg.model.pojo.QualityManageIndustryReport;
import com.ttg.web.dao.*;
import com.ttg.web.juc.TasktemplateHelper;
import com.ttg.web.service.job.IndustryDepositJobService;
import com.ttg.web.service.job.JobCommon;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.cms.PasswordRecipientId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description： 行业存贷信息任务
 * Author: chenyou
 * Date: 2025/9/2 17:23
 * Company: ttg
 * Copyright: Copyright (c) 2025
 */
@Slf4j
@Service
@TaskRunMethod(value = "industryDepositTask")
public class IndustryDepositJobServiceImpl extends JobCommon implements IndustryDepositJobService {

    @Value("${tlinx.isJuc:false}")
    private volatile Boolean isJuc;//是否启用异步回调
    @Autowired
    private TasktemplateHelper tasktemplateHelper;
    @Autowired
    private CostManageIndustryDepositLoanDao industryDepositLoanDao;
    @Autowired
    private QualityManageIndustryReportDao industryReportDao;
    @Autowired
    private ModelMctMonthDao modelMctMonthDao;
    @Autowired
    private ModelAccountMonthDao modelAccountMonthDao;
    @Autowired
    private IndustryInfoDao industryInfoDao;
    @Autowired
    private LivenessMctConfigDao livenessMctConfigDao;


    @Value("${tlinx.costmanage.effectDepMctMinAmt:1000}")
    private String effectDepMctMinAmt;
    @Value("${tlinx.costmanage.highDepMctMinAmt:59000}")
    private String highDepMctMinAmt;

    @Override
    public TaskResultVO industryDeposit(TaskBaseDTO reqDto) {
        reqDto = getCheckYearAndMonth(reqDto);
        //1.查询所有二级行业分类
        List<IndustryTwoLevelVO> list = industryInfoDao.allTwoLevelList();

        List<ListenableFuture<TaskResultVO>> futures = new ArrayList<>();
        List<TaskResultVO> results = new ArrayList<>();
        for (IndustryTwoLevelVO industry:list){
            if(isJuc){
                futures.add(tasktemplateHelper.submit(this,reqDto,industry));
            }else {
                TaskResultVO result = industryDepositTask(reqDto,industry);
                results.add(result);
            }
        }
        return taskResult(results,futures,isJuc);
    }

    public TaskResultVO industryDepositTask(TaskBaseDTO reqDto, IndustryTwoLevelVO industry){
        try {
            LivenessMctConfig livenessMctConfig = livenessMctConfigDao.getByType(LivenessMctConfigEnum.每月统计.getValue());
            IndustryDepositVO industryDepositVO = modelMctMonthDao.getIndustryDeposit(
                    reqDto.getYear(),
                    reqDto.getMonth(),
                    industry.getIndClsId2(),
                    livenessMctConfig.getLmcDays(),
                    Integer.valueOf(effectDepMctMinAmt),
                    Integer.valueOf(highDepMctMinAmt));

            List<Long> mctNos = modelMctMonthDao.getMctNoByClsId2(reqDto.getYear(), reqDto.getMonth(), industry.getIndClsId2());
            //直绑账户
            ModelAccountMonthSumVO bindAcctMonthSum = modelAccountMonthDao.getBindAcctMonthByIndustry(reqDto.getYear(),reqDto.getMonth(),1,mctNos);
            //全量账户
            ModelAccountMonthSumVO allAcctMonthSum = modelAccountMonthDao.getAllAcctMonthByIndustry(reqDto.getYear(),reqDto.getMonth(),mctNos);
            //贷款情况
            ModelAccountMonthSumVO creditAcctMonthSum = modelAccountMonthDao.getCreditAcctMonthByIndustry(reqDto.getYear(),reqDto.getMonth(),mctNos);

            CostManageIndustryDepositLoan industryDeposit = new CostManageIndustryDepositLoan();
            industryDeposit.setCmidIntervalType(reqDto.getIntervalType());
            industryDeposit.setCmidYear(reqDto.getYear());
            industryDeposit.setCmidMonth(reqDto.getMonth());
            industryDeposit.setCmidClsId1(industryDepositVO.getClsId1());
            industryDeposit.setCmidClsId2(industryDepositVO.getClsId2());

            //1. 商户情况
            //1.1 总商户数
            Integer totalMctCount = industryDepositVO.getTotalMctCount();
            industryDeposit.setCmidTotalMctCount(totalMctCount);
            //1.2 活跃商户数
            Integer activeMctCount = industryDepositVO.getLivenessMctCount();
            industryDeposit.setCmidActiveMctCount(activeMctCount);
            //1.3 存款有效户数
            Integer effectDepMctCount = industryDepositVO.getEffectDepMctCount();
            industryDeposit.setCmidEffectiveDepActCount(effectDepMctCount);
            //1.4 存款优质户数
            Integer highDepMctCount = industryDepositVO.getHighDepMctCount();
            industryDeposit.setCmidHighDepActCount(highDepMctCount);
            //1.5 授信户数
            Integer creditCount = industryDepositVO.getCreditCount();
            industryDeposit.setCmidCreditActCount(creditCount);
            //1.6 用信户数
            Integer useCreditCount = industryDepositVO.getUseCreditCount();
            industryDeposit.setCmidUseCreditActCount(useCreditCount);

            //2. 存款情况
            //2.1 直绑-月日均规模
            BigDecimal bindMonthAvgAmt = bindAcctMonthSum.getAvgAmt();
            industryDeposit.setCmidBindMonthAvgAmt(bindMonthAvgAmt);
            //2.2 直绑-月末时点规模
            BigDecimal bindMonthLastdayAmt = bindAcctMonthSum.getLastdayAmt();
            industryDeposit.setCmidBindMonthLastdayAmt(bindMonthLastdayAmt);
            //2.3 直绑-偏离度
            BigDecimal bindDeviationDegree = deviationDegree(bindMonthAvgAmt, bindMonthLastdayAmt);
            industryDeposit.setCmidBindDeviationDegree(bindDeviationDegree);
            //2.4 直绑-户均日均余额
            BigDecimal bindMctMonthAvgAmt = mctMonthAvgAmt(bindMonthAvgAmt, totalMctCount);
            industryDeposit.setCmidBindMctMonthAvgAmt(bindMctMonthAvgAmt);
            //2.5 直绑-加权利率（存款）
            BigDecimal bindWeightRate = bindAcctMonthSum.getDepositRate();
            industryDeposit.setCmidBindWeightRate(bindWeightRate);

            //2.6 全量-月日均规模
            BigDecimal monthAvgAmt = allAcctMonthSum.getAvgAmt();
            industryDeposit.setCmidMonthAvgAmt(monthAvgAmt);
            //2.7 全量-月末时点规模
            BigDecimal monthLastdayAmt = allAcctMonthSum.getLastdayAmt();
            industryDeposit.setCmidMonthLastdayAmt(monthLastdayAmt);
            //2.8 全量-偏离度
            BigDecimal deviationDegree = deviationDegree(monthAvgAmt, monthLastdayAmt);
            industryDeposit.setCmidDeviationDegree(deviationDegree);
            //2.9 全量-户均日均余额
            BigDecimal mctMonthAvgAmt = mctMonthAvgAmt(monthAvgAmt, totalMctCount);
            industryDeposit.setCmidMctMonthAvgAmt(mctMonthAvgAmt);
            //2.10 全量-加权利率（存款）
            BigDecimal weightRate = allAcctMonthSum.getDepositRate();
            industryDeposit.setCmidWeightRate(weightRate);

            //3. 贷款情况
            //3.1 授信规模
            BigDecimal creditTotalAmt = creditAcctMonthSum.getCreditAmt();
            industryDeposit.setCmidCreditTotalAmt(creditTotalAmt);
            //3.2 户均授信额
            BigDecimal creditAvgAmt = creditAvgAmt(creditTotalAmt, creditCount);
            industryDeposit.setCmidCreditAvgAmt(creditAvgAmt);
            //3.3 授信率
            BigDecimal creditRate = creditRate(creditCount, totalMctCount);
            industryDeposit.setCmidCreditRate(creditRate);
            //3.4 用信规模
            BigDecimal useCreditTotalAmt = creditAcctMonthSum.getUseCreditAmt();
            industryDeposit.setCmidUseCreditTotalAmt(useCreditTotalAmt);
            //3.5 户均用信额
            BigDecimal useCreditAvgAmt = useCreditAvgAmt(useCreditTotalAmt, useCreditCount);
            industryDeposit.setCmidUseCreditAvgAmt(useCreditAvgAmt);
            //3.6 用信率
            BigDecimal useCreditRate = useCreditRate(useCreditCount, totalMctCount);
            industryDeposit.setCmidUseCreditRate(useCreditRate);
            //3.7 加权利率（贷款）
            BigDecimal weightCreditRate = creditAcctMonthSum.getCreditRate();
            industryDeposit.setCmidCreditWeightRate(weightCreditRate);
            //3.8 存贷比
            BigDecimal ratio = ratio(useCreditTotalAmt, bindMonthAvgAmt);
            industryDeposit.setCmidRatio(ratio);
            //4. 指导分类
            QualityManageIndustryReport industryReport = industryReportDao.getByUnique(reqDto.getYear(),reqDto.getMonth(), industry.getIndClsId1(), industry.getIndClsId2());
            if (industryReport == null) {
                throw new BaseException("缺少行业质量报告记录");
            }
            industryDeposit.setCmidQtrId(industryReport.getRepQtrId());
            industryDepositLoanDao.saveOrUpd(industryDeposit);
        }catch (BaseException e) {
            e.printStackTrace();
            return taskReuslt(Status.FAIL.getValue(),false, e.getMsg());
        }catch (Exception ex){
            ex.printStackTrace();
            String exType = ex.getClass().getSimpleName();
            return taskReuslt(Status.FAIL.getValue(),false,"异常类型：" + exType + ",异常信息：" + ex.getMessage());
        }
        return taskReuslt(Status.SUCCESS.getValue(),false,"ok");
    }

    /**
     * 存款有效商户数量
     * 公式：全量商户中存款日均余额≥1000的商户数
     * todo 缺少数据来源
     */
    public Long effectDepMctCount(List<MerchTradeInfoByMonthVO> cls2MctList){
        return cls2MctList.stream().filter(o -> o.getAvgDepositAmount().compareTo(new BigDecimal(effectDepMctMinAmt))>=0).count();
    }

    /**
     * 存款优质商户数量
     * 公式：活跃商户中存款日均余额≥50000的商户数
     * todo 缺少数据来源
     */
    public Long highDepMctCount(List<MerchTradeInfoByMonthVO> cls2ActiveMctList){
        return cls2ActiveMctList.stream().filter(o -> o.getAvgDepositAmount().compareTo(new BigDecimal(highDepMctMinAmt))>=0).count();
    }

    /**
     * 授信商户数量
     * 公式：统计带有授信标识的商户数
     * todo 缺少数据来源
     */
    public Long creditCount(List<MerchTradeInfoByMonthVO> cls2MctList){
        return cls2MctList.stream().filter(o -> o.getCreditFlag().equals(String.valueOf(CreditFlagEnum.授信.getValue()))).count();
    }

    /**
     * 用信商户数量
     * 公式：统计带有用信标识的商户数
     * todo 缺少数据来源
     */
    public Long useCreditCount(List<MerchTradeInfoByMonthVO> cls2MctList){
        return cls2MctList.stream().filter(o -> o.getUseCreditFlag().equals(String.valueOf(UseCreditFlagEnum.用信.getValue()))).count();
    }

    /**
     * 直绑/全量账户-月日均规模
     * 公式：对直绑/全量账户月日均规模求和
     * todo 缺少数据来源
     */
    public Long monthAvgAmtSum(List<AccountInfoPO> acctList){
        return acctList.stream().mapToLong(o -> o.getAvgDepositAmount()==null?0:o.getAvgDepositAmount().longValue()).sum();
    }

    /**
     * 直绑/全量账户-月末时点规模
     * 公式：对直绑/全量账户月末时点规模求和
     * todo 缺少数据来源
     */
    public Long monthLastdayAmtSum(List<AccountInfoPO> acctList){
        return acctList.stream().mapToLong(o -> o.getLastDayAmount()==null?0:o.getLastDayAmount().longValue()).sum();
    }

    /**
     * 直绑/全量账户-偏离度
     * 公式：（月末时点规模-月日均规模） / 月日均规模*100%
     */
    public BigDecimal deviationDegree(BigDecimal bindMonthAvgAmt,BigDecimal bindMonthLastdayAmt){
        if(Objects.isNull(bindMonthAvgAmt)){
            throw new BaseException("月日均规模不能为空");
        }
        BigDecimal r1 = BigDecimalUtils.sub(bindMonthLastdayAmt,bindMonthAvgAmt);
        return BigDecimalUtils.mul(BigDecimalUtils.div(r1,bindMonthAvgAmt,2),new BigDecimal(100));
    }

    /**
     * 直绑/全量账户-户均日均余额
     * 公式：月日均规模/总商户数
     */
    public BigDecimal mctMonthAvgAmt(BigDecimal bindMonthAvgAmt,Integer totalMctCount){
        if(Objects.isNull(totalMctCount) || totalMctCount==0){
            throw new BaseException("总商户数不能为空");
        }
        return BigDecimalUtils.div(bindMonthAvgAmt,totalMctCount,2);
    }

    /**
     * 直绑/全量账户-加权存款利率
     * 公式：逐户对直绑/全量账户 存款利率累加/总户数
     * todo 缺少数据来源
     */
    public BigDecimal weightDepositRate(List<AccountInfoPO> acctList){
        List<BigDecimal> rateList = acctList.stream().map(o -> o.getDepositRate()).collect(Collectors.toList());
        BigDecimal total = BigDecimalUtils.add(rateList);
        return total.divide(new BigDecimal(acctList.size()),2,BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 授信规模
     * 公式：对有授信标识的全量账户求和
     * todo 缺少数据来源，暂时不确定此处是用直绑账户还是全量账户
     */
    public BigDecimal creditAmtSum(List<AccountInfoPO> acctList){
        List<BigDecimal> creditAmtlist = acctList.stream().filter(o -> o.getCreditFlag()!=null&&o.getCreditFlag().equals(String.valueOf(CreditFlagEnum.授信.getValue()))).map(o -> o.getCreditAmt()).collect(Collectors.toList());
        return BigDecimalUtils.add(creditAmtlist);
    }

    /**
     * 户均授信额
     * 公式：授信规模/授信户数
     */
    public BigDecimal creditAvgAmt(BigDecimal creditTotalAmt,Integer creditCount){
        return BigDecimalUtils.div(creditTotalAmt,creditCount,2);
    }

    /**
     * 授信率
     * 公式：授信户数/总商户数
     */
    public BigDecimal creditRate(Integer creditCount,Integer totalMctCount){
        return BigDecimalUtils.div(creditCount,totalMctCount,2);
    }

    /**
     * 用信规模
     * 公式：对有用信标识的全量账户求和
     * todo 缺少数据来源，暂时不确定此处是用直绑账户还是全量账户
     */
    public BigDecimal useCreditAmtSum(List<AccountInfoPO> acctList){
        List<BigDecimal> useCreditAmtlist = acctList.stream().filter(o -> o.getUseCreditFlag()!=null&&o.getUseCreditFlag().equals(String.valueOf(UseCreditFlagEnum.用信.getValue()))).map(o -> o.getUseCreditAmt()).collect(Collectors.toList());
        return BigDecimalUtils.add(useCreditAmtlist);
    }

    /**
     * 户均用信额
     * 公式：用信规模/用信户数
     */
    public BigDecimal useCreditAvgAmt(BigDecimal useCreditTotalAmt,Integer useCreditCount){
        return BigDecimalUtils.div(useCreditTotalAmt,useCreditCount,2);
    }

    /**
     * 用信率
     * 公式：用信户数/总商户数
     */
    public BigDecimal useCreditRate(Integer useCreditCount,Integer totalMctCount){
        return BigDecimalUtils.div(useCreditCount,totalMctCount,2);
    }

    /**
     * 加权贷款利率
     * 公式：逐户对全量账户 贷款利率求和/总账户数
     * todo 缺少数据来源
     */
    public BigDecimal weightCreditRate(List<AccountInfoPO> acctList){
        List<BigDecimal> rateList = acctList.stream().map(o -> o.getCreditRate()).collect(Collectors.toList());
        BigDecimal total = BigDecimalUtils.add(rateList);
        return BigDecimalUtils.div(total,acctList.size(),2);
    }

    /**
     * 存贷比
     * 公式：用信规模/直绑账户月日均规模 * 100%
     */
    public BigDecimal ratio(BigDecimal useCreditTotalAmt,BigDecimal bindMonthAvgAmt){
        return BigDecimalUtils.mul(BigDecimalUtils.div(useCreditTotalAmt,bindMonthAvgAmt,2),new BigDecimal(100));
    }

}
